﻿// --- 文件总结 ---------------------------------------------------------------
// @file NFBagPageOp.cpp
// 本文件实现单页签操作类 NFBagPageOp：
// - 添加路径：先叠加 AddItemToPileGrid 再落空格 AddItemToEmptyGrid
// - 删除路径：按格子/按ID/按筛选/按UUID，支持尽量/必须
// - 移动合并：跨页签移动、同类合并
// - 遍历统计：ForEach、GetItemNum
// - 提交：PreCheckCommit/Commit 将操作层写回实际容器并记录变更
// ---------------------------------------------------------------------------

#include "NFBagPageOp.h"

#include <NFBagPageGrid.h>
#include <NFBagPageInterface.h>
#include <NFComm/NFCore/NFTimeUtility.h>
#include <NFLogicCommon/NFItemCreator.h>

#include "NFBagPageOpMgrInterface.h"
#include "proto_common_bag.nanopb.h"
#include "proto_cs_cmd.nanopb.h"

/**
 * @brief 默认构造函数
 * 初始化所有成员变量为默认值
 */
NFBagPageOp::NFBagPageOp()
{
    m_pBagPageOpMgr = nullptr;
    m_pBagPageInterface = nullptr;
    m_ownerId = 0;
    m_iCapacity = 0;
    m_iBagType = 0;
}

/**
 * @brief 析构函数
 */
NFBagPageOp::~NFBagPageOp()
{
}

/**
 * @brief 添加物品到指定空格子
 * 要求格子为空且数量>=1，调用 NFItemCreator 创建新物品并设置属性
 */
int NFBagPageOp::AddItemToEmptyGridByGridIndex(const WillAddItemData& stWillAddItemData, int iNum, int iGridIndex)
{
    int iRetCode = 0;
    CHECK_EXPR(iNum >= 1, -1, "pItem->GetNumber():{} must >= 1", iNum);

    // 校验物品是否可添加到本页签
    bool bCanAdd = false;
    iRetCode = ItemCanAdd(stWillAddItemData, bCanAdd);
    CHECK_ERR(0, iRetCode, "ItemCanAdd");
    CHECK_EXPR(bCanAdd, -1, "ItemCanAdd can't add to here");

    // 获取或创建操作格子，并确保该格子为空
    auto pBagPageGrid = GetGrid(iGridIndex);
    CHECK_NULL(0, pBagPageGrid);
    CHECK_EXPR(pBagPageGrid->GetNumber() <= 0, -1, "not empty, iGridIndex:{}", iGridIndex);

    // 创建新物品：调用 NFItemCreator 并设置基础属性（数量/有效期/交易冷却/绑定）
    auto& stItem = pBagPageGrid->GetItem();
    stItem.Init();
    iRetCode = NFItemCreator::CreateItem(stWillAddItemData.id, stWillAddItemData.quality, stItem);
    CHECK_ERR(0, iRetCode, "CreateItem Failed, id:{} quality:{}", stWillAddItemData.id, stWillAddItemData.quality);
    stItem.SetNumber(iNum);
    // 有效期与交易冷却只在明确提供且合理时设置
    if (stWillAddItemData.effective_time > 0)
    {
        stItem.SetEffectTime(stWillAddItemData.effective_time);
    }
    if (stWillAddItemData.trade_cooldown > 0 && stWillAddItemData.trade_cooldown > NF_ADJUST_TIMENOW())
    {
        stItem.SetTradeCoolDown(stWillAddItemData.trade_cooldown);
    }

    stItem.SetBind(stWillAddItemData.role_bind);

    LOG_DEBUG(0, "AddItemToEmptyGrid, iBagType:{} iGridIndex:{} item:{}", GetBagType(), iGridIndex, stItem.ShortDebugString());
    return 0;
}

/**
 * @brief 仅添加物品到空格子（不尝试叠加）
 * @param pItem 要添加的物品
 * @param iWantAddNum 期望添加数量
 * @param iAddNum 输出实际添加数量
 * @return 0成功，非0失败
 */
int NFBagPageOp::AddItemOnlyToEmptyGrid(const NFGridItem* pItem, int iWantAddNum, int& iAddNum)
{
    int iRetCode = 0;
    CHECK_NULL(0, pItem);

    iAddNum = 0;
    if (iWantAddNum <= 0) // 无需添加
    {
        return 0;
    }

    if (pItem->GetNumber() < iWantAddNum) // 物品个数不够
    {
        CHECK_ERR(0, -1, "pCWare->GetNumber():%d iWantAddNum:%d", pItem->GetNumber(), iWantAddNum);
    }

    int iPileNumMax = -1;
    iRetCode = NFItemUtil::GetItemPileNumMax(pItem->GetItemID(), iPileNumMax);
    CHECK_ERR(0, iRetCode, "CServicePackage::GetWarePileNumMax");
    if (iPileNumMax <= 1)
    {
        if (pItem->GetNumber() > iPileNumMax)
        {
            CHECK_ERR(0, -1, "pItem->GetNumber():%d", pItem->GetNumber());
        }

        int iEmptyGridIndex = 0;
        iRetCode = FindFirstEmptyGrid(iEmptyGridIndex);
        CHECK_ERR(0, iRetCode, "FindFirstEmptyGrid");
        if (iEmptyGridIndex < 0)
        {
            return 0;
        }

        iRetCode = AddItemToEmptyGridByGridIndex(pItem, iEmptyGridIndex);
        CHECK_ERR(0, iRetCode, "AddItemToEmptyGrid, iEmptyGridIndex:{}", iEmptyGridIndex);
        iAddNum = pItem->GetNumber();
    }
    else
    {
        if (pItem->GetUUID() > 0 || pItem->m_uniExt.which_m_stData > 0)
        {
            LOG_ERR(m_ownerId, -1, "AddItem, iPileNumMax:{} > 1, but pItem->GetUUID():{} > 0 or pItem->m_uniExt.which_m_stData:{} > 0, the will be lost. TRACE_STACK:{}", iPileNumMax, pItem->GetUUID(), pItem->m_uniExt.which_m_stData, TRACE_STACK());
        }
        WillAddItemData stWillAddItemData = *pItem;
        iRetCode = AddItemToEmptyGrid(stWillAddItemData, iWantAddNum, iAddNum);
        CHECK_ERR(0, iRetCode, "AddItemsToPileGrid, iWantAddNum:{}", iWantAddNum);
    }
    return 0;;
}

/**
 * @brief 添加物品到指定空格子（使用现有物品对象）
 * @param pItem 要添加的物品对象
 * @param iGridIndex 目标格子索引
 * @return 0成功，非0失败
 */
int NFBagPageOp::AddItemToEmptyGridByGridIndex(const NFGridItem* pItem, int iGridIndex)
{
    int iRetCode = 0;
    CHECK_NULL(0, pItem);
    CHECK_EXPR(pItem->GetNumber() >= 1, -1, "pItem->GetNumber():{} must >= 1", pItem->GetNumber());

    bool bCanAdd = false;
    iRetCode = ItemCanAdd(pItem, bCanAdd);
    CHECK_ERR(0, iRetCode, "ItemCanAdd");
    CHECK_EXPR(bCanAdd, -1, "ItemCanAdd can't add to here");

    auto pBagPageGrid = GetGrid(iGridIndex);
    CHECK_NULL(0, pBagPageGrid);
    CHECK_EXPR(pBagPageGrid->GetNumber() <= 0, -1, "not empty, iGridIndex:{}", iGridIndex);

    if (pItem->m_iItemType == 0)
    {
        LOG_ERR(m_ownerId, -1, "AddItemToEmptyGrid, item type must > 0. item:{}", pItem->m_stBase.ShortDebugString());
        return -1;
    }

    auto& stItem = pBagPageGrid->GetItem();
    stItem.Init();
    stItem = *pItem;

    LOG_DEBUG(0, "AddItemToEmptyGrid, iGridIndex:{} item:{}", iGridIndex, stItem.ShortDebugString());
    return 0;
}

/**
 * @brief 添加物品到指定可叠加格子
 * @param stWillAddItemData 待添加物品数据
 * @param iNum 要添加的数量
 * @param iGridIndex 目标格子索引
 * @return 0成功，非0失败
 */
int NFBagPageOp::AddItemToPileGridByGridIndex(const WillAddItemData& stWillAddItemData, int iNum, int iGridIndex)
{
    int iRetCode = 0;
    CHECK_EXPR(iNum >= 1, -1, "iNum:{} must >= 1", iNum);

    bool bCanAdd = false;
    iRetCode = ItemCanAdd(stWillAddItemData, bCanAdd);
    CHECK_ERR(m_ownerId, iRetCode, "ItemCanAdd");
    CHECK_EXPR(bCanAdd, -1, "ItemCanAdd can't add to here");

    auto pBagPageGrid = GetGrid(iGridIndex);
    CHECK_NULL(m_ownerId, pBagPageGrid);
    CHECK_EXPR(pBagPageGrid->GetNumber() > 0, -1, "not empty, iGridIndex:{}", iGridIndex);

    auto pItem = &pBagPageGrid->GetItem();

    int iCanPileNumMax = 0;
    iRetCode = NFItemUtil::GetCanPileNumMax(stWillAddItemData, *pItem, iCanPileNumMax);
    CHECK_ERR(m_ownerId, iRetCode, "");
    CHECK_EXPR(iCanPileNumMax >= iNum, -1, "iCanPileNumMax:{} must >= iNum:{}", iCanPileNumMax, iNum);

    int iNowNumber = pItem->GetNumber() + iNum;
    int iRealNum = 0;
    iRetCode = SetGridNumber(*pBagPageGrid, iNowNumber, iRealNum);
    CHECK_ERR(m_ownerId, iRetCode, "SetGridNumber iGridIndex:{} iNowNumber:{}, iRealNum:{}", iGridIndex, iNowNumber, iRealNum);
    CHECK_EXPR(pItem->GetNumber() == iNowNumber, -1, "iNowNumber:{} but GetNumber:{}", iNowNumber, pItem->GetNumber());

    LOG_DEBUG(m_ownerId, "AddItemToPileGrid, iGridIndex:{} iNum:{} iCanPileNumMax:{} iRealNum:{}, item info:{}", iGridIndex, iNum, iCanPileNumMax, iRealNum, pItem->ShortDebugString());
    return 0;
}

/**
 * @brief 添加可堆叠物品，优先叠加到现有同类格子
 * 遍历所有格子，查找可叠加空间并依次累加，直至添加完成或没有空间
 * @param iAddNum 输出实际添加数量
 */
int NFBagPageOp::AddItemToPileGrid(const WillAddItemData& stWillAddItemData, int iNum, int& iAddNum)
{
    int iRetCode = 0;
    iAddNum = 0;
    // 不可堆叠或堆叠上限为1，直接跳过叠加逻辑
    int iPileNumMax = NFItemUtil::GetItemPileNumMax(stWillAddItemData.id);
    if (iPileNumMax <= 1)
    {
        return 0;
    }

    // 遍历所有格子，查找可叠加的同类物品
    for (int iGridIndex = 0; iNum > 0 && iGridIndex < GetCapacity(); ++iGridIndex)
    {
        int iCanPileNumMax = 0;
        NFGridItem* pItem = nullptr;
        NFGridItem* pOriginItem = nullptr;
        iRetCode = GetItemForCheck(iGridIndex, pItem, pOriginItem);
        // 优先检查操作层，无则检查原始层，计算当前格子还能叠加多少
        if (pItem == nullptr)
        {
            if (pOriginItem == nullptr)
            {
                continue;
            }
            iRetCode = NFItemUtil::GetCanPileNumMax(stWillAddItemData, *pOriginItem, iCanPileNumMax);
        }
        else
        {
            iRetCode = NFItemUtil::GetCanPileNumMax(stWillAddItemData, *pItem, iCanPileNumMax);
        }
        CHECK_ERR(0, iRetCode, "NFPackageUtil::GetCanPileNumMax");

        if (iCanPileNumMax < 1)
        {
            continue;
        }

        // 取剩余需添加数量与该格子可叠加上限中的较小值
        int iPileNum = iCanPileNumMax;
        if (iCanPileNumMax >= iNum)
        {
            iPileNum = iNum;
        }

        LOG_TRACE(0, "AddToPile, gridIndex:{} iNum:{}", iGridIndex, iPileNum);

        iRetCode = AddItemToPileGridByGridIndex(stWillAddItemData, iPileNum, iGridIndex);
        CHECK_ERR(0, iRetCode, "AddItemToPileGrid, iGridIndex:{} iPileNum:{}", iGridIndex, iPileNum);

        iNum -= iPileNum;
        iAddNum += iPileNum;
    }

    return 0;
}

/**
 * @brief 添加物品到可叠加格子（使用现有物品对象）
 * @param pItem 要添加的物品对象
 * @param iAddNum 输出实际添加数量
 * @return 0成功，非0失败
 */
int NFBagPageOp::AddItemToPileGrid(const NFGridItem* pItem, int& iAddNum)
{
    int iRetCode = 0;
    CHECK_NULL(0, pItem);
    CHECK_EXPR(pItem->GetUUID() == 0, -1, "pItem->GetUUID():{} must == 0", pItem->GetUUID());
    WillAddItemData stWillAddItemData = *pItem;

    iRetCode = AddItemToPileGrid(stWillAddItemData, pItem->GetNumber(), iAddNum);
    CHECK_ERR(0, iRetCode, "AddItemsToPileGrid, item:{}", pItem->ShortDebugString());
    return 0;
}

/**
 * @brief 添加物品到空格子（将剩余数量落空格，遵循每格上限）
 * @param stWillAddItemData 待添加物品数据
 * @param iNum 要添加的数量
 * @param iAddNum 输出实际添加数量
 * @return 0成功，非0失败
 */
int NFBagPageOp::AddItemToEmptyGrid(const WillAddItemData& stWillAddItemData, int iNum, int& iAddNum)
{
    int iRetCode = 0;
    iAddNum = 0;

    int iPileNumMax = NFItemUtil::GetItemPileNumMax(stWillAddItemData.id);
    CHECK_EXPR(iPileNumMax >= 1, -1, "iPileNumMax:{} must >= 0", iPileNumMax);

    int iResNum = 0;
    for (int iGridIndex = 0; iNum > 0 && iGridIndex < GetCapacity(); ++iGridIndex)
    {
        NFGridItem* pItem = nullptr;
        NFGridItem* pOriginItem = nullptr;
        iRetCode = GetItemForCheck(iGridIndex, pItem, pOriginItem);
        if (pItem == nullptr)
        {
            if (pOriginItem == nullptr)
            {
                iResNum = 0;
            }
            else
            {
                iResNum = pOriginItem->GetNumber();
            }
        }
        else
        {
            iResNum = pItem->GetNumber();
        }

        if (iResNum > 0)
        {
            continue;
        }

        int iPileNum = iPileNumMax;
        if (iPileNum >= iNum)
        {
            iPileNum = iNum;
        }

        LOG_TRACE(0, "AddToEmptyGrid, bagType:{} gridIndex:{} itemId:{} quality:{} iNum:{}",  GetBagType(), iGridIndex, stWillAddItemData.id, stWillAddItemData.quality, iPileNum);

        iRetCode = AddItemToEmptyGridByGridIndex(stWillAddItemData, iPileNum, iGridIndex);
        CHECK_ERR(0, iRetCode, "AddItemToEmptyGrid, iGridIndex:{} iPileNum:{}", iGridIndex, iPileNum);

        iNum -= iPileNum;
        iAddNum += iPileNum;
    }

    return 0;
}

/**
 * @brief 添加物品（使用物品自身数量）
 * @param pItem 要添加的物品对象
 * @param iAddNum 输出实际添加数量
 * @return 0成功，非0失败
 */
int NFBagPageOp::AddItem(const NFGridItem* pItem, int& iAddNum)
{
    CHECK_NULL(0, pItem);
    return AddItem(pItem, pItem->GetNumber(), iAddNum);
}

/**
 * @brief 添加物品（指定数量）
 * @param pItem 要添加的物品对象
 * @param iWantAddNum 期望添加数量
 * @param iAddNum 输出实际添加数量
 * @return 0成功，非0失败
 */
int NFBagPageOp::AddItem(const NFGridItem* pItem, int iWantAddNum, int& iAddNum)
{
    int iRetCode = 0;
    CHECK_NULL(0, pItem);

    iAddNum = 0;
    if (iWantAddNum <= 0) // 无需添加
    {
        return 0;
    }

    if (pItem->GetNumber() < iWantAddNum) // 物品个数不够
    {
        CHECK_ERR(0, -1, "pCWare->GetNumber():%d iWantAddNum:%d", pItem->GetNumber(), iWantAddNum);
    }

    int iPileNumMax = -1;
    iRetCode = NFItemUtil::GetItemPileNumMax(pItem->GetItemID(), iPileNumMax);
    CHECK_ERR(0, iRetCode, "CServicePackage::GetWarePileNumMax");
    if (iPileNumMax <= 1)
    {
        if (pItem->GetNumber() > iPileNumMax)
        {
            CHECK_ERR(0, -1, "pItem->GetNumber():%d", pItem->GetNumber());
        }

        int iEmptyGridIndex = 0;
        iRetCode = FindFirstEmptyGrid(iEmptyGridIndex);
        CHECK_ERR(0, iRetCode, "FindFirstEmptyGrid");
        if (iEmptyGridIndex < 0)
        {
            return 0;
        }

        iRetCode = AddItemToEmptyGridByGridIndex(pItem, iEmptyGridIndex);
        CHECK_ERR(0, iRetCode, "AddItemToEmptyGrid, iEmptyGridIndex:{}", iEmptyGridIndex);
        iAddNum = pItem->GetNumber();
    }
    else
    {
        if (pItem->GetUUID() > 0 || pItem->m_uniExt.which_m_stData > 0)
        {
            LOG_ERR(m_ownerId, -1, "AddItem, iPileNumMax:{} > 1, but pItem->GetUUID():{} > 0 or pItem->m_uniExt.which_m_stData:{} > 0, the will be lost. TRACE_STACK:{}", iPileNumMax, pItem->GetUUID(), pItem->m_uniExt.which_m_stData, TRACE_STACK());
        }
        WillAddItemData stWillAddItemData = *pItem;
        iRetCode = AddItem(stWillAddItemData, iWantAddNum, iAddNum);
        CHECK_ERR(0, iRetCode, "AddItemsToPileGrid, iWantAddNum:{}", iWantAddNum);
    }
    return 0;
}

/**
 * @brief 标准添加流程：先叠加后落空格
 * 先尝试叠加到现有同类格子，剩余部分再填充到空格子
 */
int NFBagPageOp::AddItem(const WillAddItemData& stWillAddItemData, int iNum, int& iAddNum)
{
    int iRetCode = 0;
    iAddNum = 0;
    // 第一步：尝试叠加到现有同类格子
    int iPileNum = 0;
    iRetCode = AddItemToPileGrid(stWillAddItemData, iNum, iPileNum);
    CHECK_ERR(0, iRetCode, "AddItemsToPileGrid, iNum:{} iPileNum:{}", iNum, iPileNum);
    iNum -= iPileNum;
    iAddNum += iPileNum;

    // 第二步：剩余数量填充到空格子
    if (iNum > 0)
    {
        int iToEmptyGridNum = 0;
        iRetCode = AddItemToEmptyGrid(stWillAddItemData, iNum, iToEmptyGridNum);
        CHECK_ERR(0, iRetCode, "AddItemsToEmptyGrid, iNum:{} iToEmptyGridNum:{}", iNum, iToEmptyGridNum);

        iAddNum += iToEmptyGridNum;
    }

    return 0;
}

/**
 * @brief 删除指定物品（支持归属与过期过滤）
 * 1. 收集满足条件的候选格子（按归属/过期时间过滤）
 * 2. 按删除优先级排序（绑定/品质等）
 * 3. 依次从格子中扣除数量，直到删除完成或无可用格子
 * @param ullOwnerRoldID 归属ID（0表示不校验）
 * @param pRealDelNum 非空时尽量删除，空时必须全部删除
 */
int NFBagPageOp::DelItem(uint64_t ullOwnerRoldID, int iItemId, int iWantDelNum, int* pRealDelNum)
{
    int iRetCode = 0;
    uint32_t dwDelExpireUnixSec = m_pBagPageOpMgr->GetDelExpireUnixSec();
    LOG_TRACE(m_ownerId, "m_ownerId:{} iItemId:{} iWantDelNum:{} dwDelExpireUnixSec:{}:{}"
              , ullOwnerRoldID, iItemId, iWantDelNum
              , dwDelExpireUnixSec, NFTimeUtility::DateTimeToStr(dwDelExpireUnixSec));

    // 第一步：收集满足条件的候选物品（归属/过期时间过滤）
    std::vector<ItemOpData> vecItemOpData;
    GetOpItemParam stParam;
    stParam.ullOwnerRoleID = ullOwnerRoldID;
    stParam.dwExpireUnixSec = dwDelExpireUnixSec;
    iRetCode = GetOpWareData(iItemId, &stParam, vecItemOpData);
    CHECK_ERR(m_ownerId, iRetCode, "GetOpWareData, iItemId:{} iWantDelNum:{} dwDelExpireUnixSec:{}:{}"
              , ullOwnerRoldID, iItemId, iWantDelNum
              , dwDelExpireUnixSec, NFTimeUtility::DateTimeToStr(dwDelExpireUnixSec));

    // 第二步：按删除优先级排序（优先删除绑定、低品质等）
    std::stable_sort(vecItemOpData.begin(), vecItemOpData.end(), NFItemUtil::ItemOpDataCompareFunForDel);

    // 第三步：依次从格子中扣除数量
    int iLeftWantDelNum = iWantDelNum;
    for (int i = 0; i < (int)vecItemOpData.size() && iLeftWantDelNum > 0; ++i)
    {
        auto& stItemOpData = vecItemOpData[i];

        int iThisRealDelNum = 0;
        iRetCode = DelItemByGridWithNum(stItemOpData.iGridIndex, iLeftWantDelNum, &iThisRealDelNum);
        CHECK_ERR(m_ownerId, iRetCode, "i:{} iGridIndex:{} iWantDelNum:{} iThisRealDelNum:{}", i, stItemOpData.iGridIndex, iLeftWantDelNum, iThisRealDelNum);
        // 防御性检查：实际删除数不应超过请求数
        CHECK_EXPR(iThisRealDelNum <= iLeftWantDelNum, -1, "DelItemByGridWithNum iThisRealDelNum:{} iLeftWantDelNum:{}", iThisRealDelNum, iLeftWantDelNum);
        iLeftWantDelNum -= iThisRealDelNum;
    }

    int iDelNum = iWantDelNum - iLeftWantDelNum;
    LOG_TRACE(m_ownerId, "iDelNum:{} iLeftWantDelNum:{}", iDelNum, iLeftWantDelNum);

    // 尽量删除模式：返回实际删除数量
    if (pRealDelNum)
    {
        *pRealDelNum = iDelNum;
    }
    // 必须全部删除模式：未删除完则返回错误
    else
    {
        if (iDelNum != iWantDelNum)
        {
            CHECK_ERR(m_ownerId, proto_ff::ERR_CODE_ITEM_NOT_ENOUGH, "iWantDelNum:{} iDelNUm:{}", iWantDelNum, iDelNum);
        }
    }

    return 0;
}

/**
 * @brief 删除指定物品（简化版：归属默认为当前Owner）
 * 直接调用完整版 DelItem，归属ID使用 m_ownerId
 */
int NFBagPageOp::DelItem(int iItemId, int iWantDelNum, int* pRealDelNum)
{
    int iRetCode = 0;

    LOG_TRACE(m_ownerId, "iResID:%d iWantDelNum:%d", iItemId, iWantDelNum);

    iRetCode = DelItem(m_ownerId, iItemId, iWantDelNum, pRealDelNum);
    CHECK_ERR(m_ownerId, iRetCode, "DelItems, iItemId:%d iWantDelNum:%d", iItemId, iWantDelNum);

    return 0;
}

/**
 * @brief 按格子索引扣减物品数量
 * 获取格子对象后调用格子版本的 DelItemByGridWithNum
 */
int NFBagPageOp::DelItemByGridWithNum(int iGridIndex, int iWantDecNum, int* pRealDecNum)
{
    int iRetCode = 0;

    // 非法格子，可能的，来自客户端
    auto pGrid = GetGrid(iGridIndex);
    CHECK_NULL_WF(0, pGrid, "GetGrid iGridIndex:{} iWantDecNum:{}", iGridIndex, iWantDecNum);

    iRetCode = DelItemByGridWithNum(*pGrid, iWantDecNum, pRealDecNum);
    CHECK_ERR(0, iRetCode, "DelWareByGridWithNum iGridIndex:{} iWantDecNum:{}", iGridIndex, iWantDecNum);

    return 0;
}

/**
 * @brief 按格子对象扣减物品数量
 * 调用格子的 DecNumber 减少数量，记录前后状态日志
 */
int NFBagPageOp::DelItemByGridWithNum(NFBagPageGrid& stGrid, int iWantDecNum, int* pRealDecNum)
{
    int iRetCode = 0;
    LOG_DEBUG(0, "BagType:{} GridIndex:{} item:{} iWantDecNum:{}", GetBagType(), stGrid.GetGridIndex(), stGrid.GetItem().ShortDebugString(), iWantDecNum);

    // 调用格子对象的 DecNumber 接口扣减数量
    iRetCode = stGrid.DecNumber(iWantDecNum, pRealDecNum);
    CHECK_ERR(0, iRetCode, "stGrid.DecNumber iWantDecNum:{}", iWantDecNum);

    // 记录扣减后的格子状态
    if (pRealDecNum == nullptr)
    {
        LOG_DEBUG(0, "BagType:{} GridIndex:{} after ItemId:{} UUID:{} Number:{}, dwWantDecNum:{}", GetBagType(), stGrid.GetGridIndex(), stGrid.GetItemID(), stGrid.GetUUID(), stGrid.GetNumber(), iWantDecNum);
    }
    else
    {
        LOG_DEBUG(0, "BagType:{} GridIndex:{} after ItemID:{} UUID:{} Number:{}, dwWantDecNum:{} dwRealDecNum:{}", GetBagType(), stGrid.GetGridIndex(), stGrid.GetItemID(), stGrid.GetUUID(), stGrid.GetNumber(), iWantDecNum, *pRealDecNum);
    }

    return 0;
}

/**
 * @brief 删除指定格子的全部物品
 * 通过 INT_MAX 尽量删除模式清空格子
 */
int NFBagPageOp::DelItemByGrid(int iGridIndex)
{
    int iRetCode = 0;

    int iDelNum = 0;
    // INT_MAX 格子里最大物品个数
    // &iDelNum 有多少，删多少
    iRetCode = DelItemByGridWithNum(iGridIndex, INT_MAX, &iDelNum);
    CHECK_ERR(0, iRetCode, "DelWareByGridWithNum dwGridIndex:{}", iGridIndex);

    return 0;
}

/**
 * @brief 删除指定物品ID的所有物品（不考虑绑定）
 * 选择匹配的所有格子并删除
 */
int NFBagPageOp::DelAllByItemID(int iItemId)
{
    int iRetCode = 0;

    SelectItemGridParam stParam;
    stParam.base.id = iItemId;
    stParam.selectType = SELECT_ITEM_GRID_TYPE_NOT_CONSIDER_BIND;

    iRetCode = DelAllMatchGrid(stParam);
    CHECK_ERR(0, iRetCode, "DelAllMatchGrid");

    return 0;
}

/**
 * @brief 删除所有匹配筛选条件的格子
 * 通过 SelectItemGrid 选中目标格子后，将其数量设置为 0
 */
int NFBagPageOp::DelAllMatchGrid(const SelectItemGridParam& stParam)
{
    int iRetCode = 0;
    CHECK_NULL(0, m_pBagPageInterface);

    // 选中匹配条件的所有格子
    std::vector<int> vecGridIndex;
    iRetCode = SelectItemGrid(stParam, vecGridIndex);
    CHECK_ERR(0, iRetCode, "SelectItemGrid");

    // 依次将格子数量设为 0
    int iRealNum = 0;
    for (auto iGridIndex : vecGridIndex)
    {
        iRetCode = SetGridNumber(iGridIndex, 0, iRealNum);
        CHECK_ERR(0, iRetCode, "SetGridNumber iGridIndex:{} iNum:0 iRealNum:{}"
                  , iGridIndex, iRealNum);
    }

    return 0;
}

/**
 * @brief 按筛选条件删除物品
 * 选中所有匹配条件的格子后，依次扣减直到达到目标数量
 * @param stParam 筛选条件（物品ID/绑定/品质等）
 * @param pRealDecNum 非空时尽量删除，空时必须全部删除
 */
int NFBagPageOp::DelItem(SelectItemGridParam& stParam, int iWantDecNum, int* pRealDecNum)
{
    int iRetCode = 0;
    if (pRealDecNum)
    {
        *pRealDecNum = 0;
    }

    LOG_DEBUG(0, "stParam:{} iWantDelNum:{}", stParam.GetDebugInfo(), iWantDecNum);

    if (iWantDecNum <= 0)
    {
        return 0;
    }

    // 选中所有满足条件的格子
    std::vector<int> vecGridIndexs;
    iRetCode = SelectItemGrid(stParam, vecGridIndexs);
    CHECK_ERR(0, iRetCode, "SelectItemGrid");

    // 依次从格子中扣减，直到达到目标数量或无可用格子
    int iLeftNum = iWantDecNum;
    for (auto iGridIndex : vecGridIndexs)
    {
        int iRealDelNum = 0;
        iRetCode = DelItemByGridWithNum(iGridIndex, iLeftNum, &iRealDelNum);
        CHECK_ERR(0, iRetCode, "DelItemByGridWithNum iGridIndex:{} iLeftNum:{} iRealDelNum:{}", iGridIndex, iLeftNum, iRealDelNum);
        CHECK_EXPR(iRealDelNum <= iLeftNum, -1, "DelItemByGridWithNum iGridIndex:{} iLeftNum:{} iRealDelNum:{}", iGridIndex, iLeftNum, iRealDelNum);
        if (pRealDecNum)
        {
            *pRealDecNum += iRealDelNum;
        }
        iLeftNum -= iRealDelNum;
        if (iLeftNum <= 0)
        {
            return 0;
        }
    }

    // 全部删除模式，但是没有删除够
    if (pRealDecNum == nullptr)
    {
        return proto_ff::ERR_CODE_ITEM_NOT_ENOUGH;
    }

    return 0;
}

/**
 * @brief 按物品ID与UUID删除物品
 * 遍历所有格子，找到匹配 UUID 的物品后验证 ID 并删除
 */
int NFBagPageOp::DelItemByItemIdAndUUid(int itemId, uint64_t ullItemUUid)
{
    int iRetCode = 0;

    // 遍历查找匹配 UUID 的格子
    int iDelGridIndex = INVALID_ID;
    ForEachItem([&](int iGridIndex, const NFGridItem& stItem, bool& bStop)-> int
    {
        if (stItem.GetUUID() == ullItemUUid)
        {
            // 校验物品ID是否匹配
            if (stItem.GetItemID() != itemId)
            {
                return ERR_CODE_ITEM_NOT_EXIST;
            }
            iDelGridIndex = iGridIndex;
            bStop = true;
        }
        return 0;
    });

    if (iDelGridIndex == INVALID_ID)
    {
        CHECK_ERR(0, ERR_CODE_ITEM_NOT_EXIST, "item not exist, itemId:{} ullItemUUid:{}", itemId, ullItemUUid);
    }

    // 删除找到的格子（默认删除1个）
    int iRealDelNum = 0;
    int iWantDelNum = 1;
    iRetCode = DelItemByGridWithNum(iDelGridIndex, iWantDelNum, &iRealDelNum);
    CHECK_ERR(0, iRetCode, "DelItemByGridWithNum iGridIndex:{} iWantDelNum:{} iRealDelNum:{}", iDelGridIndex, iWantDelNum, iRealDelNum);
    CHECK_EXPR(iRealDelNum <= iWantDelNum, -1, "DelItemByGridWithNum iGridIndex:{} iLeftNum:{} iRealDelNum:{}", iDelGridIndex, iWantDelNum, iRealDelNum);

    return 0;
}

/**
 * @brief 移动格子物品到另一个页签
 * 简化版接口，调用完整版 MoveOneGridItemToOtherBagPage
 */
int NFBagPageOp::MoveGridItemToBagPage(int iGridIndex, int iMoveNum, NFBagPageOp* pBagPageOp)
{
    int iRetCode = 0;
    CHECK_NULL(0, pBagPageOp);

    if (iMoveNum <= 0) // 无需移动
    {
        return 0;
    }

    iRetCode = MoveOneGridItemToOtherBagPage(iGridIndex, iMoveNum, *pBagPageOp, nullptr);
    CHECK_ERR(0, iRetCode, "MoveOneGridWareToOtherContainer iGridIndex:%d iMoveNum:%d"
        , iGridIndex, iMoveNum);

    return 0;
}

/**
 * @brief 移动单个格子的物品到另一页签（完整版）
 * 1. 检查是否为同一容器（禁止同容器移动）
 * 2. 获取源格子物品并校验数量
 * 3. 添加到目标页签（优先叠加再落空格）
 * 4. 从源格子扣减已移动的数量
 * @param iCheckNum -1表示不校验，其它值表示必须与格子数量一致
 * @param pRealMoveNum 非空时尽量移动，空时必须全部移动
 */
int NFBagPageOp::MoveOneGridItemToOtherBagPage(int iGridIndex, int iMoveNum, NFBagPageOp& stToBagPageOp, int* pRealMoveNum, int iCheckNum)
{
    int iRetCode = 0;

    // 禁止同容器内移动
    bool bEqual = false;
    iRetCode = GetEqual(&stToBagPageOp, bEqual);
    CHECK_ERR(0, iRetCode, "GetEqual");
    CHECK_EXPR(!bEqual, -1, "can`t move in same container");

    // 获取源格子物品与数量
    int iHasItemNum = 0;
    NFGridItem* pItem = nullptr;
    NFGridItem* pOriginItem = nullptr;
    iRetCode = GetItemForCheck(iGridIndex, pItem, pOriginItem);
    CHECK_ERR(0, iRetCode, "GetItemForCheck iGridIndex:%d", iGridIndex);
    if (pItem == nullptr)
    {
        CHECK_NULL_WF(0, pOriginItem, "GetItemForCheck iGridIndex:%d", iGridIndex);
        iHasItemNum = pOriginItem->GetNumber();
    }
    else
    {
        iHasItemNum = pItem->GetNumber();
    }

    // 校验格子数量（用于防止并发修改）
    if (iCheckNum != -1 && iCheckNum != iHasItemNum)
    {
        CHECK_ERR(0, -1, "iCheckNum:%d != iHasItemNum:%d", iCheckNum, iHasItemNum);
    }

    // 确定实际移动数量
    if (iMoveNum == -1) // -1 表示移动全部
    {
        iMoveNum = iHasItemNum;
    }
    else if (iMoveNum <= 0) // 无效参数
    {
        CHECK_ERR(0, -1, "invalid iMoveNum:%d", iMoveNum);
    }

    // 添加到目标页签
    int iAddNum = 0;
    if (pItem == nullptr)
    {
        iRetCode = stToBagPageOp.AddItem(pOriginItem, iMoveNum, iAddNum);
    }
    else
    {
        iRetCode = stToBagPageOp.AddItem(pItem, iMoveNum, iAddNum);
    }
    CHECK_ERR(0, iRetCode, "AddItem iGridIndex:%d iMoveNum:%d iAddNum:%d", iGridIndex, iMoveNum, iAddNum);

    // 根据模式处理未完全移动的情况
    if (pRealMoveNum) // 尽量移动，返回实际移动个数
    {
        *pRealMoveNum = iAddNum;
    }
    else // 必须全部移动
    {
        if (iAddNum < iMoveNum) // 未全部添加 只有一种可能，目标容器不可放入全部
        {// 返回背包满错误
            int iErrCode = 0;
            iRetCode = stToBagPageOp.GetErrCodeWhenFull(iErrCode);
            CHECK_ERR(0, iRetCode, "stToContainer.GetErrCodeWhenFull");
            CHECK_ERR(0, iErrCode, "stToContainer.AddWare, iAddNum=%d iMoveNum:%d"
                , iAddNum, iMoveNum);
        }
    }

    // 从源格子扣减已移动的数量
    if (iAddNum <= 0) // 未添加，不用扣除
    {
        return 0;
    }

    int iWantDecNum = iAddNum;
    iRetCode = DelItemByGridWithNum(iGridIndex, iWantDecNum, nullptr);
    CHECK_ERR(0, iRetCode, "DelItemByGridWithNum iGridIndex:%d iWantDecNum:%d", iGridIndex, iWantDecNum);

    return 0;
}

/**
 * @brief 转移相同物品ID到目标页签
 * @param pToBagPage 目标页签操作器
 * @param bHadMove 输出是否发生了移动
 * @param pNoSameItem 输出是否没有相同物品（可选）
 * @return 0成功，非0失败
 */
int NFBagPageOp::TransferSameItemId(NFBagPageOp* pToBagPage, bool& bHadMove, bool* pNoSameItem)
{
    int iRetCode = 0;
    bHadMove = false;
    CHECK_NULL(0, pToBagPage);

    bool bEqual = false;
    iRetCode = GetEqual(pToBagPage, bEqual);
    CHECK_ERR(0, iRetCode, "GetEqual");
    if (bEqual)
    {
        CHECK_ERR(0, -1, "can`t move in same container");
    }

    int iMoveNum = 0;
    for (int iFromGridIndex = 0; iFromGridIndex < GetCapacity(); ++iFromGridIndex)
    {
        bool bNoSameWareItem = false;
        iRetCode = AddOneGridToSameResID(iFromGridIndex, *pToBagPage, iMoveNum, bNoSameWareItem);
        CHECK_ERR(0, iRetCode, "AddOneGridToSameResID, iFromGridIndex:%d iMoveNum:%d"
            , iFromGridIndex, iMoveNum);
        if (iMoveNum > 0 && !bHadMove) // 记录有移动物品
        {
            bHadMove = true;
        }

        if (!bHadMove && bNoSameWareItem && pNoSameItem)
        {// 没有移动过任何物品，且没有相同的物品
            *pNoSameItem = true;
        }
    }

    return 0;
}

/**
 * @brief 将一个格子的物品添加到目标页签的相同物品ID格子
 * @param iFromGridIndex 源格子索引
 * @param stToBagPage 目标页签操作器
 * @param iMoveNum 输出移动数量
 * @param bNoSameItem 输出是否没有相同物品
 * @return 0成功，非0失败
 */
int NFBagPageOp::AddOneGridToSameResID(int iFromGridIndex, NFBagPageOp& stToBagPage, int& iMoveNum, bool& bNoSameItem)
{
    int iRetCode = 0;
    iMoveNum = 0;

    NFGridItem* pItem = nullptr;
    NFGridItem* pOriginItem = nullptr;
    iRetCode = GetItemForCheck(iFromGridIndex, pItem, pOriginItem);
    CHECK_ERR(0, iRetCode, "GetItemForCheck iFromGridIndex:{}", iFromGridIndex);

    if (pItem == nullptr)
    {
        CHECK_NULL_WF(0, pOriginItem, "GetItemForCheck iFromGridIndex:{}", iFromGridIndex);
        iRetCode = stToBagPage.AddSameItemIDToBagPage(pOriginItem, iMoveNum, bNoSameItem);
    }
    else
    {
        iRetCode = stToBagPage.AddSameItemIDToBagPage(pItem, iMoveNum, bNoSameItem);
    }

    CHECK_ERR(0, iRetCode, "AddSameItemIDToBagPage iFromGridIndex:{}", iFromGridIndex);
    if (iMoveNum <= 0)
    {
        return 0;
    }

    int iWantDecNum = iMoveNum;
    iRetCode = DelItemByGridWithNum(iFromGridIndex, iWantDecNum, nullptr);
    CHECK_ERR(0, iRetCode, "DelItemByGridWithNum iFromGridIndex:{} iWantDecNum:{}", iFromGridIndex, iWantDecNum);

    return 0;
}

/**
 * @brief 将物品添加到页签中相同物品ID的格子
 * @param pItem 要添加的物品
 * @param iAddNum 输出实际添加数量
 * @param bNoSameItem 输出是否没有相同物品
 * @return 0成功，非0失败
 */
int NFBagPageOp::AddSameItemIDToBagPage(NFGridItem* pItem, int& iAddNum, bool& bNoSameItem)
{
    int iRetCode = 0;
    CHECK_NULL(0, pItem);
    iAddNum = 0; // 初始添加个数 防止后面直接反回了 未设置
    bNoSameItem = false;

    if (pItem->GetNumber() <= 0) // 物品个数没了
    {
        return 0;
    }

    int iItemNum = 0;
    iRetCode = GetItemNum(pItem->GetItemID(), 1, iItemNum);
    LOG_DEBUG(0, "ToNumHasWare %d", iItemNum);
    CHECK_ERR(0, iRetCode, "GetWareNum");
    if (iItemNum <= 0) // 不存在相同resid的物品
    {
        bNoSameItem = true;
        return 0;
    }

    iRetCode = AddItem(pItem, iAddNum);
    CHECK_ERR(0, iRetCode, "AddItem");
    LOG_DEBUG(0, "AddItem iAddNum:%d", iAddNum);
    return 0;
}

NFGridItem* NFBagPageOp::GetMutableItem(int iGridIndex)
{
    auto pGrid = GetGrid(iGridIndex);
    CHECK_NULL_WARN_RE_NULL(0, pGrid, "GetGrid, iGridIndex:%d", iGridIndex);
    return &pGrid->GetItem();
}

/**
 * @brief 获取格子物品用于检查（单参数版本）
 * @param iGridIndex 格子索引
 * @param pOutItem 输出物品指针
 * @return 0成功，非0失败
 */
int NFBagPageOp::GetItemForCheck(int iGridIndex, NFGridItem* pOutItem)
{
    int iRetCode = 0;
    CHECK_NULL(0, pOutItem);
    NFGridItem* pItem = nullptr;
    NFGridItem* pOriginItem = nullptr;
    iRetCode = GetItemForCheck(iGridIndex, pItem, pOriginItem);
    CHECK_ERR(0, iRetCode, "GetItemForCheck, iGridIndex:{}", iGridIndex);

    if (pItem != nullptr)
    {
        *pOutItem = *pItem;
    }
    else
    {
        if (pOriginItem == nullptr)
        {
            pOutItem->SetEmpty();
        }
        else
        {
            if (pOriginItem->IsEmpty())
            {
                pOutItem->SetEmpty();
            }
            else
            {
                *pOutItem = *pOriginItem;
            }
        }
    }
    return 0;
}

/**
 * @brief 获取格子物品用于检查（返回操作层或原始层）
 * 优先返回操作层物品，若无则返回原始层物品
 * @param pOutItem 输出操作层物品指针
 * @param pOutOriginItem 输出原始层物品指针
 */
int NFBagPageOp::GetItemForCheck(int iGridIndex, NFGridItem*& pOutItem, NFGridItem*& pOutOriginItem)
{
    NFBagPageGrid* pGrid = GetExistOpGrid(iGridIndex);
    if (pGrid != nullptr) // 优先使用操作格子的物品
    {
        pOutItem = &pGrid->GetItem();
    }
    else
    {
        pOutOriginItem = GetOriginItem(iGridIndex);
    }
    return 0;
}

/**
 * @brief 获取操作层格子物品（仅返回操作层）
 * 只返回操作层物品，若无则返回 nullptr
 */
NFGridItem* NFBagPageOp::GetGridItemForCheck(int iGridIndex)
{
    NFBagPageGrid* pGrid = GetExistOpGrid(iGridIndex);
    if (pGrid != nullptr) // 优先使用操作格子的物品
    {
        return &pGrid->GetItem();
    }
    return nullptr;
}

/**
 * @brief 收集满足条件的物品操作数据
 * 遍历所有物品，筛选出满足物品ID、绑定状态、过期时间等条件的格子
 * @param pstParam 筛选参数（归属/过期时间/绑定类型）
 * @param vecItemOpData 输出满足条件的物品操作数据
 */
int NFBagPageOp::GetOpWareData(int iItemID, GetOpItemParam* pstParam, std::vector<ItemOpData>& vecItemOpData)
{
    CHECK_NULL(0, pstParam);

    LOG_TRACE(0, "iResID:{} m_ownerId:{} vecWareOpData.size():{} dwExpireUnixSec:{}:{} bindType:{}"
              , iItemID, pstParam->ullOwnerRoleID, static_cast<uint32_t>(vecItemOpData.size())
              , pstParam->dwExpireUnixSec, NFTimeUtility::DateTimeToStr(pstParam->dwExpireUnixSec), pstParam->iBindType);

    // 计算目标绑定状态
    auto pDesc = ItemDesc::Instance()->GetDesc(iItemID);
    CHECK_NULL(0, pDesc);
    bool bBind = NFItemUtil::IsBind(false, *pDesc, (enItemBindType)pstParam->iBindType);

    // 遍历所有物品，筛选满足条件的格子
    ItemOpData stItemOpData;
    stItemOpData.pBagPageOp = this;
    ForEachItem([&](int iGridIndex, const NFGridItem& stItem, bool& bStop)-> int
    {
        if (stItem.GetItemID() == iItemID && stItem.IsBind() == bBind
            // 不校验过期时刻 || 没有过期时刻 || 未到过期时刻
            && (pstParam->dwExpireUnixSec == 0 || stItem.GetEffectTime() == 0 || stItem.GetEffectTime() > pstParam->dwExpireUnixSec))
        {
            stItemOpData.iGridIndex = iGridIndex;
            stItemOpData.pItem = &stItem;
            vecItemOpData.push_back(stItemOpData);
        }

        return 0;
    });

    return 0;
}

/**
 * @brief 统计指定物品的数量（无上限）
 * 简化版本，最大数量为 int 最大值
 */
int NFBagPageOp::GetItemNum(int iItemId, int& iItemNum)
{
    return GetItemNum(iItemId, std::numeric_limits<int>::max(), iItemNum);
}

/**
 * @brief 统计指定物品的数量（带上限）
 * 遍历所有格子，累加匹配物品ID的物品数量，达到上限则停止
 */
int NFBagPageOp::GetItemNum(int iItemId, int iMaxNum, int& iItemNum)
{
    int iRetCode = 0;
    iItemNum = 0;

    NFGridItem* pOutItem = nullptr;
    // 物品一般放在容器的前面 这里从前往后遍历计算
    for (int iGridIndex = 0; iGridIndex < GetCapacity(); ++iGridIndex)
    {
        NFGridItem* pItem = nullptr;
        NFGridItem* pOriginItem = nullptr;
        iRetCode = GetItemForCheck(iGridIndex, pItem, pOriginItem);
        CHECK_ERR(0, iRetCode, "GetWareForCheck iGridIndex:%d", iGridIndex);

        if (pItem == nullptr)
        {
            if (pOriginItem == nullptr)
            {
                continue;
            }

            pOutItem = pOriginItem;
        }
        else
        {
            pOutItem = pItem;
        }
        CHECK_NULL(0, pOutItem);

        if (pOutItem->GetItemID() == iItemId && pOutItem->GetNumber() > 0)
        {
            iItemNum += pOutItem->GetNumber();
            if (iItemNum >= iMaxNum)
            {
                break;
            }
        }
    }

    return 0;
}

/**
 * @brief 检查格子索引是否有效
 * @param iGridIndex 格子索引
 * @return 0有效，-1无效
 */
int NFBagPageOp::CheckGridIndex(int iGridIndex) const
{
    if (iGridIndex < 0 || iGridIndex >= GetCapacity())
    {
        CHECK_ERR(0, -1, "invalid iGridIndex:%d, must in [0, %d)", iGridIndex, GetCapacity());
    }
    return 0;
}

/**
 * @brief 查找第一个空格子
 * @param iGridIndexOut 输出空格子索引
 * @return 0成功，非0失败
 */
int NFBagPageOp::FindFirstEmptyGrid(int& iGridIndexOut)
{
    int iRetCode = 0;
    iGridIndexOut = -1;
    for (int iGridIndex = 0; iGridIndex < GetCapacity(); ++iGridIndex)
    {
        NFGridItem* pItem = nullptr;
        NFGridItem* pOriginItem = nullptr;
        iRetCode = GetItemForCheck(iGridIndex, pItem, pOriginItem);
        CHECK_ERR(0, iRetCode, "GetItemForCheck");
        if (pItem == nullptr)
        {
            if (pOriginItem == nullptr)
            {
                iGridIndexOut = iGridIndex;
                break;
            }
            if (pOriginItem->GetNumber() <= 0) // 空槽
            {
                iGridIndexOut = iGridIndex;
                break;
            }
        }
        else
        {
            if (pItem->GetNumber() <= 0) // 空槽
            {
                iGridIndexOut = iGridIndex;
                break;
            }
        }
    }

    return 0;
}

/**
 * @brief 检查是否存在指定格子
 * @param iGridIndex 格子索引
 * @return true存在，false不存在
 */
bool NFBagPageOp::HaveGrid(int iGridIndex) const
{
    if (iGridIndex >= 0 && iGridIndex < (int)m_astGridList.size())
    {
        if (m_astGridList[iGridIndex] != nullptr)
        {
            return true;
        }
    }
    return false;
}

/**
 * @brief 获取页签满时的错误码
 * @param iErrCode 输出错误码
 * @return 0成功，非0失败
 */
int NFBagPageOp::GetErrCodeWhenFull(int& iErrCode)
{
    iErrCode = -1;
    int iRetCode = 0;
    auto pInterface = GetBagPageInterface();
    CHECK_NULL(0, pInterface);
    iRetCode = pInterface->GetErrCodeWhenFull(iErrCode);
    CHECK_ERR(0, iRetCode, "pInterface->GetErrCodeWhenFull");

    if (iErrCode == 0) // 不允许错误码=0
    {
        LOG_ERR(0, -1, "iErrCode is 0");
        iErrCode = -1;
    }
    return 0;
}

/**
 * @brief 设置格子物品数量
 * @param iGridIndex 格子索引
 * @param iNum 要设置的数量
 * @param iRealNum 输出实际设置的数量
 * @return 0成功，非0失败
 */
int NFBagPageOp::SetGridNumber(int iGridIndex, int iNum, int& iRealNum)
{
    int iRetCode = 0;

    // 非法格子，可能的，来自客户端
    auto pCWareContainerGrid = GetGrid(iGridIndex);
    CHECK_NULL_WF(0, pCWareContainerGrid, "GetGrid dwGridIndex:%u dwNum:%u dwRealNum:%u", iGridIndex, iNum, iRealNum);

    iRetCode = SetGridNumber(*pCWareContainerGrid, iNum, iRealNum);
    CHECK_ERR(0, iRetCode, "SetGridNumber dwGridIndex:%u dwNum:%u dwRealNum:%u", iGridIndex, iNum, iRealNum);

    return 0;
}

/**
 * @brief 设置格子物品数量（格子对象版本）
 * @param stGrid 格子对象
 * @param iNum 要设置的数量
 * @param iRealNum 输出实际设置的数量
 * @return 0成功，非0失败
 */
int NFBagPageOp::SetGridNumber(NFBagPageGrid& stGrid, int iNum, int& iRealNum)
{
    int iRetCode = 0;
    CHECK_EXPR(iNum >= 0, -1, "iNum:%d", iNum);

    LOG_TRACE(0, "GridIndex:{} before ResID:{} UUID:{} Number:{}, dwNum:{} dwRealNum:{}"
              , stGrid.GetGridIndex(), stGrid.GetItemID(), stGrid.GetUUID(), stGrid.GetNumber(), iNum, iRealNum);

    iRetCode = stGrid.SetNumber(iNum, iRealNum);
    CHECK_ERR(0, iRetCode, "stGrid.SetNumber dwNum:{} dwRealNum:{}"
               , iNum, iRealNum);

    LOG_TRACE(0, "GridIndex:{} after ResID:{} UUID:{} Number:{}, dwNum:{} dwRealNum:{}"
              , stGrid.GetGridIndex(), stGrid.GetItemID(), stGrid.GetUUID(), stGrid.GetNumber(), iNum, iRealNum);

    return 0;
}

/**
 * @brief 选择符合条件的物品格子
 * @param stParam 筛选参数
 * @param vecGridIndexs 输出符合条件的格子索引列表
 * @return 0成功，非0失败
 */
int NFBagPageOp::SelectItemGrid(const SelectItemGridParam& stParam, std::vector<int>& vecGridIndexs)
{
    return ForEachItem([&](int iGridIndex, const NFGridItem& stItem, bool& bStop)-> int
    {
        if (stParam.selectType == SELECT_ITEM_GRID_TYPE_ALL)
        {
            if (NFItemUtil::IsSameItem(stParam, stItem))
            {
                vecGridIndexs.push_back(iGridIndex);
            }
        }
        else if (stParam.selectType == SELECT_ITEM_GRID_TYPE_NOT_CONSIDER_BIND)
        {
            if (NFItemUtil::IsSameItemNotConsiderBind(stParam, stItem))
            {
                vecGridIndexs.push_back(iGridIndex);
            }
        }

        return 0;
    });
}

/**
 * @brief 检查物品是否可以添加到本页签
 * @param stWillAddItemData 待添加物品数据
 * @param bCanAdd 输出是否可以添加
 * @return 0成功，非0失败
 */
int NFBagPageOp::ItemCanAdd(const WillAddItemData& stWillAddItemData, bool& bCanAdd)
{
    int iRetCode = 0;

    auto pBagPagInterface = GetBagPageInterface();
    CHECK_NULL(0, pBagPagInterface);

    iRetCode = pBagPagInterface->ItemCanAdd(stWillAddItemData, bCanAdd);
    CHECK_ERR(0, iRetCode, "pCWareContainerInterface->WareCanAdd");

    return 0;
}

/**
 * @brief 检查物品是否可以添加到本页签（物品对象版本）
 * @param pItem 物品对象
 * @param bCanAdd 输出是否可以添加
 * @return 0成功，非0失败
 */
int NFBagPageOp::ItemCanAdd(const NFGridItem* pItem, bool& bCanAdd)
{
    CHECK_NULL(0, pItem);

    WillAddItemData stWillAddItemData = *pItem;
    return ItemCanAdd(stWillAddItemData, bCanAdd);
}

/**
 * @brief 比较两个页签操作器是否相等
 * @param pOther 另一个页签操作器
 * @param bEqual 输出是否相等
 * @return 0成功，非0失败
 */
int NFBagPageOp::GetEqual(const NFBagPageOp* pOther, bool& bEqual) const
{
    CHECK_NULL(0, pOther);

    auto pCWareContainerInterfaceThis = GetBagPageInterface();
    CHECK_NULL(0, pCWareContainerInterfaceThis);

    auto pCWareContainerInterfaceOther = pOther->GetBagPageInterface();
    CHECK_NULL(0, pCWareContainerInterfaceOther);

    bEqual = pCWareContainerInterfaceThis->Equal(pCWareContainerInterfaceOther);
    return 0;
}

NFBagPageGrid* NFBagPageOp::GetGrid(int iGridIndex)
{
    int iRetCode = 0;

    auto* pGrid = GetExistOpGrid(iGridIndex);
    if (pGrid != nullptr) // 已存在格子
    {
        return pGrid; // 直接返回
    }

    // 没有存在的格子 需要创建一个
    iRetCode = CreateGrid(iGridIndex, pGrid);
    CHECK_ERR_RE_NULL(0, iRetCode, "CreateGrid, iGridIndex:%d", iGridIndex);

    return pGrid;
}

NFBagPageGrid* NFBagPageOp::GetExistOpGrid(int iGridIndex)
{
    int iRetCode = 0;

    iRetCode = CheckGridIndex(iGridIndex);
    CHECK_ERR_RE_NULL(0, iRetCode, "CheckGridIndex, iGridIndex:%d", iGridIndex);

    return GetOpGridByIndex(iGridIndex);
}

NFBagPageGrid* NFBagPageOp::GetOpGridByIndex(int iGridIndex)
{
    if (iGridIndex >= 0 && iGridIndex < (int)m_astGridList.size())
    {
        return m_astGridList[iGridIndex];
    }

    return nullptr;
}

const NFBagPageGrid* NFBagPageOp::GetOpGridByIndex(int iGridIndex) const
{
    if (iGridIndex >= 0 && iGridIndex < (int)m_astGridList.size())
    {
        return m_astGridList[iGridIndex];
    }

    return nullptr;
}

NFGridItem* NFBagPageOp::GetExistMutableItem(int iGridIndex)
{
    auto pGrid = GetExistOpGrid(iGridIndex);
    CHECK_NULL_RE_NULL(0, pGrid, "");
    return &pGrid->GetItem();
}

/**
 * @brief 提交所有操作格子到真实容器
 * 依次提交所有操作格子，汇总物品变更记录并调用前后回调
 * 注意：单格子提交失败不阻塞其他格子（记录错误但继续）
 */
int NFBagPageOp::Commit(std::unordered_map<int, int>& opWareRec)
{
    int iRetCode = 0;

    // 提交前回调：用于记录提交前状态
    iRetCode = GetBagPageInterface()->OnCommitBefore();
    CHECK_ERR(0, iRetCode, "OnCommitBefore");

    // 依次提交所有操作过的格子
    for (int i = 0; i < (int)m_astGridIndexList.size(); i++)
    {
        int iGridIndex = m_astGridIndexList[i];
        NFBagPageGrid* pCurGrid = GetOpGridByIndex(iGridIndex);
        CHECK_NULL(0, pCurGrid);
        iRetCode = CommitGrid(pCurGrid);
        // 单格子失败不阻塞其它提交（非常严重，必须记录堆栈）
        if (iRetCode != 0)
        {
           LOG_ERR(0, iRetCode, "CommitGrid, iGridIndex:{} TRACE_STACK:{}", iGridIndex, TRACE_STACK());
        }
    }

    // 合并本页签的物品数量变更记录到总记录
    for (auto& pairValue : m_astItemNumChange)
    {
        opWareRec[pairValue.first] += pairValue.second;
    }

    // 提交后回调：失败不影响提交结果（容错模式）
    iRetCode = GetBagPageInterface()->OnCommitAfter(this);
    CHECK_ERR_NT(0, iRetCode, "OnCommitAfter");

    return 0;
}

/**
 * @brief 提交单个格子到真实容器
 * 比较提交前后的物品状态，判定操作类型（添加到空/删除/数量变动/UUID替换）
 * 并将变更写入实际容器，记录物品增减统计
 * @param bPreCheckFlag 预检模式：不真正写库，仅记录提交前快照
 */
int NFBagPageOp::CommitGrid(NFBagPageGrid* pCurGrid, bool bPreCheckFlag)
{
    int iRetCode = 0;
    CHECK_NULL(0, pCurGrid);
    CHECK_EXPR(!pCurGrid->IsCommit(), -1, "grid had commit");

    // 获取原始物品（提交前真实容器中的物品），用于对比判定操作类型
    NFGridItem* pOriginItem = nullptr;
    iRetCode = GetBagPageInterface()->GetItem(pCurGrid->GetGridIndex(), pOriginItem);
    CHECK_ERR(0, iRetCode, "GetBagPageInterface->GetItem");

    // 根据提交前后状态判定格子操作类型（添加到空/删除/数量变动/替换）
    EN_BAG_GRID_OP_TYPE enGridOpType = EN_BAG_GRID_OP_TYPE_NULL;
    int iItemIDForAdd = 0;
    int iItemNumForAdd = 0;
    int iItemIDForDel = 0;
    int iItemNumForDel = 0;
    // 情况1：操作前格子为空
    if (pOriginItem == nullptr || pOriginItem->GetNumber() <= 0)
    {
        if (pCurGrid->GetNumber() <= 0) // 操作后依然为空：无实质变更
        {
            return 0;
        }
        else
        {
            enGridOpType = EN_BAG_GRID_OP_TYPE_ADD_TO_EMPTY_GRID;
            iItemIDForAdd = pCurGrid->GetItemID();
            iItemNumForAdd = pCurGrid->GetNumber();
        }
    }
    // 情况2：操作前格子有物品
    else
    {
        // 记录原有物品作为"被删除"项（可能整个清空或被替换）
        if (pOriginItem->GetNumber() > 0)
        {
            iItemIDForDel = pOriginItem->GetItemID();
            iItemNumForDel = pOriginItem->GetNumber();
        }

        if (pCurGrid->GetNumber() <= 0) // 操作后格子清空
        {
            enGridOpType = EN_BAG_GRID_OP_TYPE_DEL_GRID;
        }
        else // 操作后格子仍有物品：数量变动/属性变动/物品替换
        {
            // 通过 UUID 判定是否为同一物品实例
            if (pOriginItem->GetUUID() == pCurGrid->GetUUID()) // 同一物品
            {
                if (pCurGrid->GetNumber() != pOriginItem->GetNumber()) // 数量变动（增加或减少）
                {
                    enGridOpType = EN_BAG_GRID_OP_TYPE_NUM_CHANGE;
                }
                else // 数量未变，但可能属性变动（如装备强化）
                {
                    enGridOpType = EN_BAG_GRID_OP_TYPE_NUM_NOT_CHANGE;
                }
            }
            else // UUID变动：物品整个被替换（旧UUID消失，新UUID出现）
            {
                enGridOpType = EN_BAG_GRID_OP_TYPE_ITEM_CHANGE;
            }

            // 记录新物品作为"新增"项
            iItemIDForAdd = pCurGrid->GetItemID();
            iItemNumForAdd = pCurGrid->GetNumber();
        }
    }

    // 预检模式：仅保存提交前快照，不真正写库
    if (bPreCheckFlag)
    {
        if (pOriginItem != nullptr)
        {
            iRetCode = pCurGrid->SetCommitBeforeWare(*pOriginItem);
            CHECK_ERR(0, iRetCode, "SetCommitBeforeWare");
        }
    }
    else
    {
        // 正式提交模式：可在此处针对特定操作类型执行额外逻辑
        // 当前预留：背包整理等特殊操作可在此添加处理
        if (enGridOpType == EN_BAG_GRID_OP_TYPE_ADD_TO_EMPTY_GRID || enGridOpType == EN_BAG_GRID_OP_TYPE_ITEM_CHANGE)
        {
            // 背包整理等底层操作不经过此逻辑，此处预留扩展点
        }
    }

    // 将操作格子的新状态写入真实容器
    iRetCode = GetBagPageInterface()->SetItem(this, pCurGrid->GetGridIndex(), &pCurGrid->GetItem(), bPreCheckFlag);
    CHECK_ERR(0, iRetCode, "SetItem");

    // 预检模式结束，不继续后续统计
    if (bPreCheckFlag)
    {
        return 0;
    }

    // 标记格子操作类型（用于后续通知与日志）
    pCurGrid->SetGridOpType(enGridOpType);
    // 记录本页签物品数量变更（增减合并）
    if (iItemIDForAdd != 0)
    {
        m_astItemNumChange[iItemIDForAdd] += iItemNumForAdd;
    }
    if (iItemIDForDel != 0)
    {
        m_astItemNumChange[iItemIDForDel] -= iItemNumForDel;
    }
    return 0;
}

/**
 * @brief 初始化页签操作器
 * @param pBagPageMgr 背包页签操作管理器
 * @param pBagPageInterface 背包页签接口
 * @return 0成功，非0失败
 */
int NFBagPageOp::Init(NFBagPageOpMgrInterface* pBagPageMgr, NFBagPageInterface* pBagPageInterface)
{
    int iRetCode = 0;
    CHECK_NULL(0, pBagPageMgr);
    CHECK_NULL(0, pBagPageInterface);

    int iCapacity = 0;
    iRetCode = pBagPageInterface->GetCapacity(iCapacity);
    CHECK_ERR(0, iRetCode, "GetCapacity");
    CHECK_EXPR(iCapacity <= BAG_PAGE_CAPACITY_MAX, -1, "capacity:{} must <= max:{}", iCapacity, BAG_PAGE_CAPACITY_MAX);

    int iBagType = 0;
    iRetCode = pBagPageInterface->GetBagType(iBagType);
    CHECK_ERR(0, iRetCode, "GetBagType");

    m_pBagPageOpMgr = pBagPageMgr;
    m_ownerId = pBagPageMgr->GetOwnerId();
    m_pBagPageInterface = pBagPageInterface;

    m_astGridList.resize(iCapacity);
    m_iCapacity = iCapacity;
    m_iBagType = iBagType;

    return 0;
}

/**
 * @brief 标记使用的格子
 * @param iGridIndex 格子索引
 * @return 0成功，非0失败
 */
int NFBagPageOp::SetUseGrid(int iGridIndex)
{
    m_astGridIndexList.push_back(iGridIndex);
    return 0;
}

/**
 * @brief 创建操作格子
 * @param iGridIndex 格子索引
 * @param pGrid 输出创建的格子指针
 * @return 0成功，非0失败
 */
int NFBagPageOp::CreateGrid(int iGridIndex, NFBagPageGrid*& pGrid)
{
    int iRetCode = 0;

    iRetCode = CheckGridIndex(iGridIndex);
    CHECK_ERR(0, iRetCode, "CheckGridIndex, iGridIndex:%d", iGridIndex);

    if (HaveGrid(iGridIndex))
    {
        CHECK_ERR(0, -1, "!!! iGridIndex:%d had exsit op grid", iGridIndex);
    }

    pGrid = new NFBagPageGrid();
    CHECK_NULL_WF(0, pGrid, "new NFBagPageGrid");

    iRetCode = pGrid->SetGridIndex(iGridIndex);
    CHECK_ERR(0, iRetCode, "pGrid->SetGridIndex, iGridIndex:%d", iGridIndex);
    iRetCode = SetUseGrid(iGridIndex);
    CHECK_ERR(0, iRetCode, "SetUseGrid, iGridIndex:{}", iGridIndex);
    m_astGridList[iGridIndex] = pGrid;

    NFGridItem* pOriginItem = GetOriginItem(iGridIndex);
    if (pOriginItem && !pOriginItem->IsEmpty())
    {
        pGrid->GetItem().CopyData(*pOriginItem);
    }
    return 0;
}

NFGridItem* NFBagPageOp::GetOriginItem(int iGridIndex)
{
    int iRetCode = 0;
    NFGridItem* pItem = nullptr;
    iRetCode = GetBagPageInterface()->GetItem(iGridIndex, pItem);
    CHECK_ERR_RE_NULL(0, iRetCode, "GetItem, iGridIndex:{}", iGridIndex);
    return pItem;
}

/**
 * @brief 遍历所有物品（完整版本，提供原始物品和操作物品）
 * @param func 遍历回调函数
 * @return 0成功，非0失败
 */
int NFBagPageOp::ForEachItem(const std::function<int(int iGridIndex, NFGridItem* pOriginItem, NFGridItem* pItem, bool& bStop)>& func)
{
    int iRetCode = 0;

    // 遍历所有格子
    for (int iGridIndex = 0; iGridIndex < GetCapacity(); ++iGridIndex)
    {
        NFGridItem* pItem = nullptr;
        NFGridItem* pOriginItem = nullptr;
        iRetCode = GetItemForCheck(iGridIndex, pItem, pOriginItem);
        CHECK_ERR(0, iRetCode, "GetWareForCheck");

        int iNumber = 0;
        if (pItem == nullptr)
        {
            if (pOriginItem == nullptr)
            {
                continue;
            }
            iNumber = pOriginItem->GetNumber();
        }
        else
        {
            iNumber = pItem->GetNumber();
        }

        if (iNumber <= 0)
        {
            continue;
        }

        bool bStop = false;
        iRetCode = func(iGridIndex, pOriginItem, pItem, bStop);
        CHECK_ERR(0, iRetCode, "func, iGridIndex:{}", iGridIndex);
        if (bStop)
        {
            break;
        }
    }

    return 0;
}

/**
 * @brief 遍历所有物品（配置描述版本）
 * @param func 遍历回调函数，提供物品配置描述
 * @return 0成功，非0失败
 */
int NFBagPageOp::ForEachItemDesc(const std::function<int(int iGridIndex, const E_Item* pItem, bool& bStop)>& func)
{
    return ForEachItem([&](int iGridIndex, NFGridItem* pOriginItem, NFGridItem* pItem, bool& bStop)-> int
    {
        const E_Item* pItemDesc = nullptr;
        if (pOriginItem)
        {
            pItemDesc = ItemDesc::Instance()->GetDesc(pOriginItem->GetItemID());
        }
        else if (pItem)
        {
            pItemDesc = ItemDesc::Instance()->GetDesc(pItem->GetItemID());
        }
        CHECK_NULL(0, pItemDesc);

        int iRetCode = func(iGridIndex, pItemDesc, bStop);
        CHECK_ERR(0, iRetCode, "func, iGridIndex:{}", iGridIndex);

        return 0;
    });
}

/**
 * @brief 遍历所有物品（const引用版本）
 * @param func 遍历回调函数
 * @return 0成功，非0失败
 */
int NFBagPageOp::ForEachItem(const std::function<int(int iGridIndex, const NFGridItem& stItem, bool& bStop)>& func)
{
    return ForEachItem([&](int iGridIndex, NFGridItem* pOriginItem, NFGridItem* pGridItem, bool& bStop)-> int
    {
        const NFGridItem* pItem = nullptr;
        if (pOriginItem)
        {
            pItem = pOriginItem;
        }
        else if (pGridItem)
        {
            pItem = pGridItem;
        }
        CHECK_NULL(0, pItem);

        int iRetCode = func(iGridIndex, *pItem, bStop);
        CHECK_ERR(0, iRetCode, "func, iGridIndex:{}", iGridIndex);

        return 0;
    });
}

/**
 * @brief 预检查提交（保存快照但不真正写库）
 * @return 0成功，非0失败
 */
int NFBagPageOp::PreCheckCommit()
{
    int iRetCode = 0;

    iRetCode = GetBagPageInterface()->OnCommitBefore(true);
    CHECK_ERR(0, iRetCode, "OnCommitBefore PreCheck");

    for (int i = 0; i < (int)m_astGridIndexList.size(); i++)
    {
        int iGridIndex = m_astGridIndexList[i];
        NFBagPageGrid* pCurGrid = GetOpGridByIndex(iGridIndex);
        CHECK_NULL(0, pCurGrid);
        iRetCode = CommitGrid(pCurGrid, true);
        if (iRetCode != 0) // 不应该有失败 这里只打印错误 不阻塞其它提交 tnm报告，非常严重
        {
            LOG_ERR(0, iRetCode, "CommitGrid, iGridIndex:{}", iGridIndex);
            return iRetCode;
        }
    }

    return 0;
}

/**
 * @brief 填充背包信息通知（增删都填充）
 * @param pNtf 通知消息对象
 * @param nOPReason 操作原因
 * @return 0成功，非0失败
 */
int NFBagPageOp::FillPackageInfoNotify(proto_ff::Proto_CSRoleItemNtf* pNtf, int nOPReason)
{
    CHECK_NULL(0, pNtf);
    CHECK_NULL(0, GetBagPageInterface());
    int iBagType = GetBagType();
    FF_IG_LIST* pNtfList = NFItemUtil::MutableList(pNtf, iBagType);

    if (iBagType == EN_BPT_TEMP_STORAGE)
    {
        GetBagPageInterface()->Sort();
        for (int i = 0; i < (int)GetCapacity(); i++)
        {
            auto pItem = GetOriginItem(i);
            if (pItem)
            {
                if (pItem->IsEmpty()) break;
                NFItemUtil::AddToNtf(pItem, pNtfList, i);
            }
        }
    }
    else
    {
        for (int i = 0; i < (int)m_astGridIndexList.size(); i++)
        {
            int iGridIndex = m_astGridIndexList[i];
            NFBagPageGrid* pCurGrid = GetOpGridByIndex(iGridIndex);
            CHECK_NULL(0, pCurGrid);
            if (pCurGrid->IsCommit())
            {
                auto pItem = GetOriginItem(iGridIndex);
                if (pItem)
                {
                    NFItemUtil::AddToNtf(pItem, pNtfList, iGridIndex);
                }
                else
                {
                    pNtfList->Add()->set_index(iGridIndex);
                }
            }
        }
    }

    return 0;
}

/**
 * @brief 填充背包信息通知（仅添加）
 * @param pNtf 通知消息对象
 * @param nOPReason 操作原因
 * @return 0成功，非0失败
 */
int NFBagPageOp::FillPackageInfoForAdd(proto_ff::Proto_CSRoleItemNtf* pNtf, int nOPReason)
{
    CHECK_NULL(0, pNtf);
    CHECK_NULL(0, GetBagPageInterface());
    int iBagType = GetBagType();
    FF_IG_LIST* pNtfList = NFItemUtil::MutableList(pNtf, iBagType);

    for (int i = 0; i < (int)m_astGridIndexList.size(); i++)
    {
        int iGridIndex = m_astGridIndexList[i];
        NFBagPageGrid* pCurGrid = GetOpGridByIndex(iGridIndex);
        CHECK_NULL(0, pCurGrid);
        if (pCurGrid->IsCommit())
        {
            auto& stBeforeItem = pCurGrid->GetCommitBeforeItem();
            auto& stCurItem = pCurGrid->GetItem();
            if (stCurItem.GetNumber() > stBeforeItem.GetNumber())
            {
                NFItemUtil::AddToNtfChangeNum(&stCurItem, pNtfList,  stCurItem.GetNumber() - stBeforeItem.GetNumber());
            }
        }
    }

    return 0;
}

/**
 * @brief 填充背包信息通知（仅删除）
 * @param pNtf 通知消息对象
 * @param nOPReason 操作原因
 * @return 0成功，非0失败
 */
int NFBagPageOp::FillPackageInfoForDel(proto_ff::Proto_CSRoleItemNtf* pNtf, int nOPReason)
{
    CHECK_NULL(0, pNtf);
    CHECK_NULL(0, GetBagPageInterface());
    int iBagType = GetBagType();
    FF_IG_LIST* pNtfList = NFItemUtil::MutableList(pNtf, iBagType);

    for (int i = 0; i < (int)m_astGridIndexList.size(); i++)
    {
        int iGridIndex = m_astGridIndexList[i];
        NFBagPageGrid* pCurGrid = GetOpGridByIndex(iGridIndex);
        CHECK_NULL(0, pCurGrid);
        if (pCurGrid->IsCommit())
        {
            auto& stBeforeItem = pCurGrid->GetCommitBeforeItem();
            auto& stCurItem = pCurGrid->GetItem();
            if (stCurItem.GetNumber() < stBeforeItem.GetNumber())
            {
                NFItemUtil::AddToNtfChangeNum(&stBeforeItem, pNtfList,  stBeforeItem.GetNumber() - stCurItem.GetNumber());
            }
        }
    }

    return 0;
}
